Go 起手式之二


Posted by Nacho on 2020-03-28

指標

在Go的世界中,指標意思是存取一個值在記憶的位置。

  • & 取得變數記憶體位置
  • * 透過記憶體位置取得變數值
func main() {
    i, j := 42, 2701

    // 取值的方法
    p := &i         // &i 表示 p 得到了 i 在記憶體中的位置
    fmt.Println(*p) // *p 表示 透過 p 所記錄的記憶體位置,幫我拿到 i 的值,印出 42

    // 存值的方法
    *p = 21         // 透過 p 所記錄的記憶體位置,我給定一個新的值
    fmt.Println(i)  // 印出 21

    p = &j         // &j 表示 p 得到了 j 在記憶體中的位置
    *p = *p / 37   // 拿 j 的值除以 37 並將這個新的值指給 j 
    fmt.Println(j) // 印出 73
}

資料結構

Array

在Go的世界中,如果想對陣列的size做規範可以採用array

// array的宣告,給定一個size
var a [2]string
a[0] = "Hello"
a[1] = "World"
a[2] = "!" // error 超出size
// 初始化陣列
b := [6]int{2, 3, 5, 7, 11, 13}

Slice

在Go的世界中,如果對陣列的大小希望保持彈性就採用slice。

// 只要不給定一個size,就是告訴 Go 這是一個 slice 的宣告
s := []int{2, 3, 5, 7, 11, 13}

// 沒有初始化就是 nil
var s []int // 是 nil不是 0 喔!!
len(s) // 長度才是 0
cap(s) // 容量也是 0

在Go的世界中,array和slice都具有length和capacity的屬性,不一樣的是array是固定的,無法被切割(run)

  • length就是slice裡現有元素的數量
  • capacity對應到slice原有的元素的數量
func printSlice(s []int) { 
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s) // len=6 cap=6 [2 3 5 7 11 13]

    // 切割這個 slice 使它的 length 為零
    s = s[:0]
    printSlice(s) // len=0 cap=6 []

    // 擴張這個 slice 使它的 length 為 4
    s = s[:4]
    printSlice(s) // len=4 cap=6 [2 3 5 7]

    // 移除掉前兩個元素,改變原來的容量
    s = s[2:]
    printSlice(s) // len=2 cap=4 [5 7]
}

擴充slice的長度和裁減範圍

s := []int{0, 1, 2, 3}
fmt.Println(s)    // [0 1 2 3]
// 增加長度
s = append(s, 4, 5)
fmt.Println(s)        // [0, 1, 2, 3, 4, 5]
// 也可將它裁切
fmt.Println(arr[1:4])   // [1, 2, 3]
fmt.Println(arr[1:])    // [1, 2, 3, 4, 5]

struct

設計一個可以複用的結構(stuct)來開發

// 宣告一個 struct
type Rectangle struct {
    H int
    W int
}
// 宣告一個 method
func (r Rectangle) Area() int {
    return r.H * r.W
}

func main() {
    rec := Rectangle{H: 10, W: 5}
    // rec := Rectangle{10, 5} 也可以註明 H 和 W
    fmt.Println(rec.Area()) // 10 x 5 = 50

    rec.W = 10
    fmt.Println(rec.Area()) // 10 x 10 = 100
}

(補充)結構指標

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    p := &v // 讓 p 取得 v 的記憶體位置
    p.X = 6 // (*p).X = 6 也是可以,但不必這麼做
    fmt.Println(v) // 印出 {6 2}
}

Map

Map 是一個鍵值配對(key/value)的結構。鍵是唯一的,而值可以重複。
宣告方式

// 宣告一個變數是 map 它包含一個鍵(String)一個值(int) 
var x map[string]int // 未初始化,所以會產生一個 nil map,也就是沒有任何 key

// 初始化宣告,給定一個key和value
var x = map[string]int{"apple": 1}

// 短宣告,給定一個key和value
x := map[string]int{"apple": 1}

// 初始化多組 key/value
elements := map[string]string{
    "H": "Hydrogen",
    "He": "Helium",
    "Li": "Lithium",
    "Be": "Beryllium",
    "B": "Boron",
    "C": "Carbon",
    "N": "Nitrogen",
    "O": "Oxygen",
    "F": "Fluorine",
    "Ne": "Neon",
}

賦予值的方式

// Example1: 新增一個鍵與值
x["apple"] = 1
x["banana"] = 5
fmt.Println(x) // 印出 map[apple:1 banana:5]
fmt.Println(x["banana"]) // 印出 5

// Example2: 刪除某個鍵
delete(x,"banana") // (map, key name)

// Example3: 查詢map的長度
len(x)

印出不存在的鍵
通常在編譯的時候會報錯,但執行中(go run)的 Map 不會,而是丟出空值。

name, ok := elements["Al"]
fmt.Println(name, ok) // 印出 空值 false
// 修正後
if name, ok := elements["Al"]; ok {
    fmt.Println(name, ok)
}

設計一個 Nested Map

elements := map[string]map[string]string{
    "H": map[string]string{
        "name":"Hydrogen",
        "state":"gas",
    },
    "He": map[string]string{
        "name":"Helium",
        "state":"gas",
    },
    "Li": map[string]string{
        "name":"Lithium",
        "state":"solid",
    },
    "Be": map[string]string{
        "name":"Beryllium",
        "state":"solid",
    },
    "B":  map[string]string{
        "name":"Boron",
        "state":"solid",
    },
    "C":  map[string]string{
        "name":"Carbon",
        "state":"solid",
    },
    "N":  map[string]string{
        "name":"Nitrogen",
        "state":"gas",
    },
    "O":  map[string]string{
        "name":"Oxygen",
        "state":"gas",
    },
    "F":  map[string]string{
        "name":"Fluorine",
        "state":"gas",
    },
    "Ne":  map[string]string{
        "name":"Neon",
        "state":"gas",
    },
}

if el, ok := elements["Li"]; ok {
    fmt.Println(el["name"], el["state"])
}

range

當有了array或slice或map這種集合資料的結構,我們可能需要從這些集合中找到某一個值或列出所有的值,因此,我們可以給定一個range來代表這些集合

numbers := [4]int{1, 2, 3} 
for i,x:= range numbers {
    fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)
}
// 第 0 位 x 的值 = 1
// 第 1 位 x 的值 = 2
// 第 2 位 x 的值 = 3
// 第 3 位 x 的值 = 0

m := map[string]int{
    "one": 1,
    "two": 2,
}

for k, v := range m {
    fmt.Printf("%s -> %d\n", k, v)
}
// one -> 1
// two -> 2

筆記參考

Larry Lu 的2019 iT 邦幫忙鐵人賽
官方文件


#Go Pointer #Go Slice #Go Struct #Go Map #Go Range







Related Posts

Spring boot系列(一)前言

Spring boot系列(一)前言

6. SpringBoot使用jms聆聽多個MQ(依據yml動態新增)

6. SpringBoot使用jms聆聽多個MQ(依據yml動態新增)

The introduction and difference between class component and function component in React

The introduction and difference between class component and function component in React


Comments